package com.elecemp.security.handle;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/*import org.springframework.security.web.util.AntUrlPathMatcher;
 import org.springframework.security.web.util.UrlMatcher; */
import org.springframework.stereotype.Service;

/**
 * 最核心的地方，就是提供某个资源对应的权限定义，即getAttributes方法返回的结果。 此类在初始化时，应该取到所有资源及其对应角色的定义。
 * 
 */
@Service
public class MyInvocationSecurityMetadataSourceService implements
		FilterInvocationSecurityMetadataSource {

	// @Autowired
	// private PubAuthoritiesResourcesHome pubAuthoritiesResourcesHome;
	@Autowired(required = true)
	private DataSource dataSource;

	// @Resource
	// private AuthoritiesMapper authoritiesMapper;
	//
	// @Resource
	// private AuthoritiesResourcesMapper authoritiesResourcesMapper;

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public MyInvocationSecurityMetadataSourceService(DataSource dataSource) {
		this.dataSource = dataSource;
		loadResourceDefine();
	}

	public MyInvocationSecurityMetadataSourceService() {
	}

	private void loadResourceDefine() {

		// 在Web服务器启动时，提取系统中的所有权限。
		List<String> authNames = new ArrayList<String>();
		try (Connection con = dataSource.getConnection();
				PreparedStatement st = con
						.prepareStatement(" select role_name from e_role ")) {
			ResultSet rs = st.executeQuery();
			while (rs.next()) {
				authNames.add(rs.getString("role_name"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		/**//*
			 * 应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。
			 * 一个资源可以由多个权限来访问。 sparta
			 */
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		List<String> resources = new ArrayList<String>();
		for (String auth : authNames) {
			ConfigAttribute ca = new SecurityConfig(auth);
			try (Connection con = dataSource.getConnection();
					PreparedStatement st = con
							.prepareStatement(" select resource_string from e_role r inner join e_role_resources rr on r.role_id = rr.role_id inner join e_resources res on rr.res_id=res.resource_id where r.role_name = ? ")) {
				st.setString(1, auth);
				ResultSet rs = st.executeQuery();
				while (rs.next()) {
					resources.add(rs.getString("resource_string"));
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}

			for (String res : resources) {
				String url = res;
				/*
				 * 判断资源文件和权限的对应关系，如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中
				 * sparta
				 */
				if (resourceMap.containsKey(url)) {
					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(ca);
					resourceMap.put(url, value);
				} else {
					Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
					atts.add(ca);
					resourceMap.put(url, atts);
				}

			}

		}

	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {

		return null;
	}

	// 根据URL，找到相关的权限配置。
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		// object 是一个URL，被用户请求的url。
		/**
		 * 3.0 version
		 *
		 * String url = ((FilterInvocation) object).getRequestUrl();
		 * 
		 * int firstQuestionMarkIndex = url.indexOf("?");
		 * 
		 * if (firstQuestionMarkIndex != -1) { url = url.substring(0,
		 * firstQuestionMarkIndex); }
		 * 
		 * Iterator<String> ite = resourceMap.keySet().iterator();
		 * 
		 * while (ite.hasNext()) { String resURL = ite.next();
		 * 
		 * if (urlMatcher.pathMatchesUrl(url, resURL)) {
		 * 
		 * return resourceMap.get(resURL); } }
		 */
		// 3.2 version or more
		FilterInvocation filterInvocation = (FilterInvocation) object;
		Iterator<String> ite = resourceMap.keySet().iterator();
		while (ite.hasNext()) {
			String requestURL = ite.next();
			RequestMatcher requestMatcher = new AntPathRequestMatcher(
					requestURL);
			if (requestMatcher.matches(filterInvocation.getHttpRequest())) {
				return resourceMap.get(requestURL);
			}
		}
		return null;
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return true;
	}

	// public AuthoritiesMapper getAuthoritiesMapper() {
	// return authoritiesMapper;
	// }
	//
	// public void setAuthoritiesMapper(AuthoritiesMapper authoritiesMapper) {
	// this.authoritiesMapper = authoritiesMapper;
	// }
	//
	// public AuthoritiesResourcesMapper getAuthoritiesResourcesMapper() {
	// return authoritiesResourcesMapper;
	// }
	//
	// public void setAuthoritiesResourcesMapper(
	// AuthoritiesResourcesMapper authoritiesResourcesMapper) {
	// this.authoritiesResourcesMapper = authoritiesResourcesMapper;
	// }

}